﻿using Facebook;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;

namespace Niknak.Social.Facebook
{
    /// <summary>
    /// Provides basic methods to retrieve likes from Facebook
    /// </summary>
    public static class Likes
    {
        /// <summary>
        /// Describes the types of Facebook cursors
        /// </summary>
        public enum CursorType
        {
            /// <summary>
            /// For the previous page
            /// </summary>
            Before,
            /// <summary>
            /// For the next page
            /// </summary>
            After
        }

        private const int DEFAULTPAGESIZE = 25;
        private const string GRAPHPATH = "/{0}/likes?limit={1}{2}";

        /// <summary>
        /// Gets a list of users who've liked the specified post, wrapped by a container object with additional information about the request
        /// </summary>
        /// <param name="accessToken">Facebook access token</param>
        /// <param name="postId">ID of the post to get liked for</param>
        public static LikesData GetPostLikes(string accessToken, string postId)
        {
            return GetPostLikes(accessToken, postId, DEFAULTPAGESIZE, null, CursorType.Before);
        }

        /// <summary>
        /// Gets a list of users who've liked the specified post, wrapped by a container object with additional information about the request
        /// </summary>
        /// <param name="accessToken">Facebook access token</param>
        /// <param name="postId">ID of the post to get liked for</param>
        /// <param name="pageSize">Limit the response to the specified page size</param>
        public static LikesData GetPostLikes(string accessToken, string postId, int pageSize)
        {
            return GetPostLikes(accessToken, postId, pageSize, null, CursorType.Before);
        }

        /// <summary>
        /// Gets a list of users who've liked the specified post, wrapped by a container object with additional information about the request
        /// </summary>
        /// <param name="accessToken">Facebook access token</param>
        /// <param name="postId">ID of the post to get liked for</param>
        /// <param name="pageSize">Limit the response to the specified page size</param>
        /// <param name="cursor">Use the specified cursor ID from a previous page-limited request</param>
        /// <param name="cursorType">The type of cursor specified (before or after)</param>
        public static LikesData GetPostLikes(string accessToken, string postId, int pageSize, string cursor, CursorType cursorType)
        {
            LikesData returnData = new LikesData()
            { 
                Users = new Dictionary<string,string>(),
                StartOfStream = true,
                EndOfStream = true 
            };

            string requestPath = string.Format(
                GRAPHPATH,
                postId,
                pageSize,
                !string.IsNullOrEmpty(cursor) ? cursorType == CursorType.Before ? "&before=" + cursor.Replace("=", "%3D") : "&after=" + cursor.Replace("=", "%3D") : ""
            );

            FacebookClient fbClient = new FacebookClient(accessToken);
            JObject postComments = JObject.Parse(fbClient.Get(requestPath).ToString());

            if (postComments.Property("data") != null)
            {
                foreach (JObject like in postComments.Value<JArray>("data"))
                    returnData.Users.Add(like.Value<string>("id"), like.Value<string>("name"));
            }

            if (postComments.Property("paging") != null)
            {
                if (postComments.Value<JObject>("paging").Property("cursors") != null)
                {
                    returnData.BeforeCursor = postComments["paging"]["cursors"].Value<string>("before");
                    returnData.AfterCursor = postComments["paging"]["cursors"].Value<string>("after");
                }

                if (postComments.Value<JObject>("paging").Property("previous") != null)
                    returnData.StartOfStream = false;
                if (postComments.Value<JObject>("paging").Property("next") != null)
                    returnData.EndOfStream = false;
            }

            return returnData;
        }

        /// <summary>
        /// Container for Likes data
        /// </summary>
        public struct LikesData
        {
            /// <summary>
            /// Users who like the specified object
            /// </summary>
            public Dictionary<string, string> Users;
            /// <summary>
            /// Cursor for current results page
            /// </summary>
            public string BeforeCursor;
            /// <summary>
            /// Cursor for next results page
            /// </summary>
            public string AfterCursor;
            /// <summary>
            /// True when there are is no previous page
            /// </summary>
            public bool StartOfStream;
            /// <summary>
            /// True when there are is no next page
            /// </summary>
            public bool EndOfStream;
        }
    }
}
